// @Author EthanScriptOn
// @Desc
package config_node

import (
	"errors"
	"gitee.com/fatzeng/srf_switch_basic_components/initialization"
	"gitee.com/fatzeng/srf_switch_basic_components/node"
	"gitee.com/fatzeng/srf_switch_config/config_define"
	"math"
)

var freightOrder = func() *initialization.OnceInitializer {
	initializerInstance := initialization.GenerateOnceInitializer(config_define.ParserPositionTag, config_define.FreightOrderInitTag)
	if err := initializerInstance.Set(math.MaxInt, func() (result interface{}, err error) {
		return []config_define.FreightOrder{config_define.EnvOrder, config_define.CliOrder, config_define.FileOrder}, nil
	}); err != nil {
		panic(err)
	}
	return initializerInstance
}()

func GetFreightOrder() ([]config_define.FreightOrder, error) {
	freightOrderInstance, err := freightOrder.Get()
	if err != nil {
		return nil, err
	}
	freightOrders, ok := freightOrderInstance.([]config_define.FreightOrder)
	if !ok {
		return nil, errors.New("the freightOrder instance type is not []config_config_define.FreightOrder")
	}
	return freightOrders, nil
}

type ResultManager struct {
	resultLink           *ParseResultPackageNode
	processedResultLink  *ParseResultPackageNode
	resultClassification map[config_define.FreightOrder]*ParseResultPackageNode
}

func GenerateResultManager() *ResultManager {
	return new(ResultManager)
}

func (r *ResultManager) GetProcessedResult() *ParseResultPackageNode {
	return r.processedResultLink
}

func (r *ResultManager) GetUnProcessedResult() *ParseResultPackageNode {
	return r.resultLink
}

func (r *ResultManager) StoreResult(freightOrder config_define.FreightOrder, resultNode *ParseResultPackageNode) error {
	copyResultNode := resultNode.DeepCopy()
	freightOrderPackageNode, ok := r.resultClassification[freightOrder]
	if !ok {
		r.resultClassification[freightOrder] = copyResultNode
	} else {
		if err := freightOrderPackageNode.SlotNode(node.TAIL, copyResultNode); err != nil {
			return err
		}
	}
	if r.resultLink == nil {
		r.resultLink = resultNode
	} else {
		return r.resultLink.SlotNode(node.TAIL, resultNode)
	}
	return nil
}

func (r *ResultManager) Sort() error {
	freightOrders, err := GetFreightOrder()
	if err != nil {
		return err
	}
	var finalResultNode *ParseResultPackageNode
	for f := len(freightOrders) - 1; f >= 0; f-- {
		freightOrderVar := freightOrders[f]
		packageNodes, ok := r.resultClassification[freightOrderVar]
		if !ok {
			continue
		}
		linkDeepCopy, err := packageNodes.LinkDeepCopy()
		if err != nil {
			return err
		}
		if finalResultNode == nil {
			finalResultNode = linkDeepCopy
			continue
		}
		if err = finalResultNode.SlotNode(node.TAIL, linkDeepCopy); err != nil {
			return err
		}
	}
	r.processedResultLink = finalResultNode
	return nil
}
